// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
//

use axum::Router;
use axum_app::{database::DatabaseManager, iroh_wrapper::IrohNodeWrapper};
use rig_app::{AgentManager, ToolManager};
use rusqlite::ffi::{sqlite3, sqlite3_api_routines, sqlite3_auto_extension};
use sqlite_vec::sqlite3_vec_init;
use std::sync::Arc;
use tauri::{async_runtime, State}; // Modified import
use tauri_axum::{handle_request, LocalRequest, RequestResult, StreamChunk, StreamManager};
use tokio::sync::Mutex;

type SqliteExtensionFn =
    unsafe extern "C" fn(*mut sqlite3, *mut *mut i8, *const sqlite3_api_routines) -> i32;

// Removed: use tokio::task;

struct AppState {
    router: Arc<Mutex<Router>>,
    stream_manager: Arc<Mutex<StreamManager>>,
}

#[tauri::command]
async fn local_app_request(
    state: State<'_, AppState>,
    local_request: LocalRequest,
) -> Result<RequestResult, String> {
    let mut router = state.router.lock().await;
    let mut stream_manager = state.stream_manager.lock().await;

    let result = handle_request(local_request, &mut router, &mut stream_manager).await;
    Ok(result)
}

#[tauri::command]
async fn get_stream_chunk(
    state: State<'_, AppState>,
    stream_id: String,
) -> Result<Option<StreamChunk>, String> {
    let mut stream_manager = state.stream_manager.lock().await;
    let chunk = stream_manager.get_next_chunk(&stream_id).await;
    Ok(chunk)
}

#[tauri::command]
async fn close_stream(state: State<'_, AppState>, stream_id: String) -> Result<(), String> {
    let mut stream_manager = state.stream_manager.lock().await;
    stream_manager.close_stream(&stream_id);
    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    // Initialize the `sqlite-vec`extension
    // See: https://alexgarcia.xyz/sqlite-vec/rust.html
    unsafe {
        sqlite3_auto_extension(Some(std::mem::transmute::<*const (), SqliteExtensionFn>(
            sqlite3_vec_init as *const (),
        )));
    }
    // Create AgentManager and ToolManager instances
    let agent_manager =
        Arc::new(AgentManager::new("agents.json").expect("Failed to create AgentManager"));
    let tool_manager =
        Arc::new(ToolManager::new("mcp.json").expect("Failed to create ToolManager"));

    // Create IrohNodeWrapper instance
    let iroh_node = Arc::new(IrohNodeWrapper::default());

    // Start Iroh node in a separate Tauri asynchronous runtime task
    println!("Attempting to open Iroh node...");
    let iroh_node_clone = iroh_node.clone();
    async_runtime::spawn(async move {
        match iroh_node_clone.open_node().await {
            Ok(_) => println!("Iroh node opened successfully."),
            Err(e) => eprintln!("Failed to open Iroh node: {}", e),
        }
    });

    // Create DatabaseManager instance
    let database =
        Arc::new(DatabaseManager::new("app.db").expect("Failed to create DatabaseManager"));

    let app_router = axum_app::create_axum_app(agent_manager, tool_manager, iroh_node, database);
    let app_state = AppState {
        router: Arc::new(Mutex::new(app_router)),
        stream_manager: Arc::new(Mutex::new(StreamManager::new())),
    };

    tauri::Builder::default()
        .manage(app_state)
        .invoke_handler(tauri::generate_handler![
            local_app_request,
            get_stream_chunk,
            close_stream
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
